package com.kristin.proxy.jdk;

import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKProxyMainTest {

    interface Animal {

        void call();

    }

    static class Dog implements Animal {

        @Override
        public void call() {
            System.out.println("发出狗叫");
        }
    }

    static class Cat implements Animal {

        @Override
        public void call() {
            System.out.println("发出猫叫");
        }
    }

    public static void main(String[] args) throws Exception {
        // 获取代理类文件
        new JDKProxyMainTest().getProxyFile(new Dog());


        // 分步获取代理对象
        Animal dogProxy = (Animal)getProxyByStep(new Dog());
        dogProxy.call();

        System.out.println("==============================");

        // 直接使用Proxy.newProxyInstance方法获取代理对象
        Animal dogProxy2 = (Animal)getProxyImmediately(new Cat());
        dogProxy2.call();
    }

    void getProxyFile(Object target) throws Exception{
        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("step1...");
                Object result = method.invoke(target, args);
                System.out.println("step2...");
                return result;
            }
        });
        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", target.getClass().getInterfaces());
//        String path = this.getClass().getResource("").getPath() + "Proxy.class";
        String path = "D:/Proxy.class";
        try(FileOutputStream fos = new FileOutputStream(path)) {
            fos.write(classFile);
            fos.flush();
            System.out.println("代理类class文件写入成功");
        } catch (Exception e) {
            System.out.println("写文件错误");
        }
    }



    static Object getProxyByStep(Object target) throws Exception {
        Class clazz = Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces());
        Constructor constructor = clazz.getConstructor(InvocationHandler.class);
        return constructor.newInstance(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("方法开始...");
                Object result = method.invoke(target, args);
                System.out.println("方法结束...");
                return result;
            }
        });
    }

    static Object getProxyImmediately(Object target) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("方法开始...");
                Object result = method.invoke(target, args);
                System.out.println("方法结束...");
                return result;
            }
        });
    }

}
